//go:build acceptance || all

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package test

import (
	"regexp"
	"testing"

	"github.com/bpg/terraform-provider-proxmox/utils"
	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
	"github.com/hashicorp/terraform-plugin-testing/plancheck"
)

func TestAccResourceVMDisks(t *testing.T) {
	t.Parallel()

	te := InitEnvironment(t)

	tests := []struct {
		name  string
		steps []resource.TestStep
	}{
		{"create disk with default parameters, then update it", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 8
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
						"disk.0.aio":               "io_uring",
						"disk.0.backup":            "true",
						"disk.0.cache":             "none",
						"disk.0.discard":           "ignore",
						"disk.0.file_id":           "",
						"disk.0.datastore_id":      "local-lvm",
						"disk.0.file_format":       "raw",
						"disk.0.interface":         "virtio0",
						"disk.0.iothread":          "false",
						"disk.0.path_in_datastore": `vm-\d+-disk-\d+`,
						"disk.0.replicate":         "true",
						"disk.0.size":              "8",
						"disk.0.ssd":               "false",
					}),
				),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"

					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						serial	     = "-dead_beef-"
						size         = 8
						replicate    = false
						aio          = "native"
						backup       = "false"
						speed {
						  iops_read = 100
						  iops_read_burstable = 1000
						  iops_write = 400
						  iops_write_burstable = 800
						}
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
						"disk.0.aio":                          "native",
						"disk.0.backup":                       "false",
						"disk.0.cache":                        "none",
						"disk.0.discard":                      "ignore",
						"disk.0.file_id":                      "",
						"disk.0.datastore_id":                 "local-lvm",
						"disk.0.file_format":                  "raw",
						"disk.0.interface":                    "virtio0",
						"disk.0.iothread":                     "false",
						"disk.0.path_in_datastore":            `vm-\d+-disk-\d+`,
						"disk.0.replicate":                    "false",
						"disk.0.serial":                       "-dead_beef-",
						"disk.0.size":                         "8",
						"disk.0.ssd":                          "false",
						"disk.0.speed.0.iops_read":            "100",
						"disk.0.speed.0.iops_read_burstable":  "1000",
						"disk.0.speed.0.iops_write":           "400",
						"disk.0.speed.0.iops_write_burstable": "800",
					}),
				),
			},
		}},
		{"create disk from an image", []resource.TestStep{{
			Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_download_file" "test_disk_image" {
					content_type = "iso"
					datastore_id = "local"
					node_name    = "{{.NodeName}}"
					url          = "{{.CloudImagesServer}}/minimal/releases/noble/release/ubuntu-24.04-minimal-cloudimg-amd64.img"
					overwrite_unmanaged = true
				}
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"	
					disk {
						datastore_id = "local-lvm"
						file_id      = proxmox_virtual_environment_download_file.test_disk_image.id
						interface    = "virtio0"
						iothread     = true
						discard      = "on"
						serial       = "dead_beef"
						size         = 20
					}
				}`),
			Check: resource.ComposeTestCheckFunc(
				ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
					"disk.0.cache":             "none",
					"disk.0.datastore_id":      "local-lvm",
					"disk.0.discard":           "on",
					"disk.0.file_format":       "raw",
					"disk.0.interface":         "virtio0",
					"disk.0.iothread":          "true",
					"disk.0.path_in_datastore": `vm-\d+-disk-\d+`,
					"disk.0.serial":            "dead_beef",
					"disk.0.size":              "20",
					"disk.0.ssd":               "false",
				}),
			),
		}}},
		{"import disk from an image", []resource.TestStep{{
			Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_download_file" "test_disk_image" {
					content_type = "import"
					datastore_id = "local"
					node_name    = "{{.NodeName}}"
					url          = "{{.CloudImagesServer}}/minimal/releases/noble/release/ubuntu-24.04-minimal-cloudimg-amd64.img"
					file_name    = "test-disk-image.img.raw"
					overwrite_unmanaged = true
				}
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"	
					disk {
						datastore_id = "local-lvm"
						import_from  = proxmox_virtual_environment_download_file.test_disk_image.id
						interface    = "virtio0"
						iothread     = true
						discard      = "on"
						serial       = "dead_beef"
						size         = 20
					}
				}`),
			Check: resource.ComposeTestCheckFunc(
				ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
					"disk.0.cache":             "none",
					"disk.0.datastore_id":      "local-lvm",
					"disk.0.discard":           "on",
					"disk.0.file_format":       "raw",
					"disk.0.interface":         "virtio0",
					"disk.0.iothread":          "true",
					"disk.0.path_in_datastore": `vm-\d+-disk-\d+`,
					"disk.0.serial":            "dead_beef",
					"disk.0.size":              "20",
					"disk.0.ssd":               "false",
				}),
			),
		}}},
		{"clone default disk without overrides", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_template" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk-template"
					template  = "true"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 8
					}
				}
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"

					clone {
						vm_id = proxmox_virtual_environment_vm.test_disk_template.id
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					// fully cloned disk, does not have any attributes in state
					resource.TestCheckNoResourceAttr("proxmox_virtual_environment_vm.test_disk", "disk.0"),
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{}),
				),
			},
			{
				RefreshState: true,
			},
		}},
		{"multiple disks", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"
					template  = "true"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 8
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
					"disk.0.interface":         "virtio0",
					"disk.0.path_in_datastore": `base-\d+-disk-1`,
					"disk.1.interface":         "scsi0",
					"disk.1.path_in_datastore": `base-\d+-disk-0`,
				}),
			},
			{
				RefreshState: true,
			},
		}},
		{"disk ordering consistency", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_ordering" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk-ordering"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio2"
						size         = 8
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 15
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "sata0"
						size         = 12
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 10
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 20
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi3"
						size         = 5
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio1"
						size         = 18
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi2"
						size         = 25
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disk_ordering", map[string]string{
					"disk.0.interface": "virtio2",
					"disk.0.size":      "8",
					"disk.1.interface": "scsi1",
					"disk.1.size":      "15",
					"disk.2.interface": "sata0",
					"disk.2.size":      "12",
					"disk.3.interface": "scsi0",
					"disk.3.size":      "10",
					"disk.4.interface": "virtio0",
					"disk.4.size":      "20",
					"disk.5.interface": "scsi3",
					"disk.5.size":      "5",
					"disk.6.interface": "virtio1",
					"disk.6.size":      "18",
					"disk.7.interface": "scsi2",
					"disk.7.size":      "25",
				}),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_ordering" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk-ordering"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio2"
						size         = 8
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 15
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "sata0"
						size         = 12
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 10
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 20
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi3"
						size         = 5
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio1"
						size         = 18
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi2"
						size         = 25
					}
				}`),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectEmptyPlan(),
					},
				},
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disk_ordering", map[string]string{
					"disk.0.interface": "virtio2",
					"disk.0.size":      "8",
					"disk.1.interface": "scsi1",
					"disk.1.size":      "15",
					"disk.2.interface": "sata0",
					"disk.2.size":      "12",
					"disk.3.interface": "scsi0",
					"disk.3.size":      "10",
					"disk.4.interface": "virtio0",
					"disk.4.size":      "20",
					"disk.5.interface": "scsi3",
					"disk.5.size":      "5",
					"disk.6.interface": "virtio1",
					"disk.6.size":      "18",
					"disk.7.interface": "scsi2",
					"disk.7.size":      "25",
				}),
			},
			{
				// Third apply to ensure consistency across multiple applies
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_ordering" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk-ordering"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio2"
						size         = 8
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 15
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "sata0"
						size         = 12
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 10
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 20
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi3"
						size         = 5
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio1"
						size         = 18
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi2"
						size         = 25
					}
				}`),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectEmptyPlan(),
					},
				},
			},
		}},
		{"adding disks", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
					"disk.0.interface":         "scsi0",
					"disk.0.path_in_datastore": `vm-\d+-disk-0`,
				}),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}

					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 8
					}
				}`),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectResourceAction("proxmox_virtual_environment_vm.test_disk", plancheck.ResourceActionUpdate),
					},
				},
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
					"disk.0.interface":         "scsi0",
					"disk.0.path_in_datastore": `vm-\d+-disk-0`,
					"disk.1.interface":         "scsi1",
					"disk.1.path_in_datastore": `vm-\d+-disk-1`,
				}),
			},
			{
				RefreshState: true,
			},
		}},
		{"removing disks", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}

					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 8
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
					"disk.0.interface":         "scsi0",
					"disk.0.path_in_datastore": `vm-\d+-disk-0`,
					"disk.1.interface":         "scsi1",
					"disk.1.path_in_datastore": `vm-\d+-disk-1`,
				}),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}
				}`),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectResourceAction("proxmox_virtual_environment_vm.test_disk", plancheck.ResourceActionUpdate),
					},
				},
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
					"disk.0.interface":         "scsi0",
					"disk.0.path_in_datastore": `vm-\d+-disk-0`,
					"disk.#":                   "1", // Verify only one disk remains
				}),
			},
			{
				RefreshState: true,
			},
		}},
		{"boot disk deletion protection", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_boot_protection" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-boot-protection"
					
					boot_order = ["scsi0", "net0"]
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}

					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 8
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_boot_protection", map[string]string{
					"disk.0.interface": "scsi0",
					"disk.1.interface": "scsi1",
					"boot_order.0":     "scsi0",
					"boot_order.1":     "net0",
				}),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_boot_protection" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-boot-protection"
					
					boot_order = ["scsi0", "net0"]
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 8
					}
				}`),
				ExpectError: regexp.MustCompile(`cannot delete boot disk "scsi0"`),
			},
		}},
		{"non-boot disk deletion works", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_non_boot_deletion" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-non-boot-deletion"
					
					boot_order = ["scsi0", "net0"]
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}

					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 8
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_non_boot_deletion", map[string]string{
					"disk.0.interface": "scsi0",
					"disk.1.interface": "scsi1",
					"boot_order.0":     "scsi0",
					"boot_order.1":     "net0",
				}),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_non_boot_deletion" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-non-boot-deletion"
					
					boot_order = ["scsi0", "net0"]
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}
				}`),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectResourceAction("proxmox_virtual_environment_vm.test_non_boot_deletion", plancheck.ResourceActionUpdate),
					},
				},
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_non_boot_deletion", map[string]string{
					"disk.0.interface": "scsi0",
					"disk.#":           "1", // Verify only boot disk remains
				}),
			},
			{
				RefreshState: true,
			},
		}},
		{"issue #2172 exact bug scenario", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "debian_git01" {
					node_name = "{{.NodeName}}"
					started   = false
					name      = "git01"
					
					boot_order = ["scsi0", "net0"]
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 32
					}

					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 20
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi2"
						size         = 1
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi3"
						size         = 50
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi4"
						size         = 1
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi5"
						size         = 50
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi6"
						size         = 1
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi7"
						size         = 4
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.debian_git01", map[string]string{
					"disk.#":           "8", // All 8 disks present
					"disk.0.interface": "scsi0",
					"disk.0.size":      "32",
					"disk.1.interface": "scsi1",
					"disk.1.size":      "20",
					"disk.2.interface": "scsi2",
					"disk.2.size":      "1",
					"disk.3.interface": "scsi3",
					"disk.3.size":      "50",
					"disk.4.interface": "scsi4",
					"disk.4.size":      "1",
					"disk.5.interface": "scsi5",
					"disk.5.size":      "50",
					"disk.6.interface": "scsi6",
					"disk.6.size":      "1",
					"disk.7.interface": "scsi7",
					"disk.7.size":      "4",
					"boot_order.0":     "scsi0",
					"boot_order.1":     "net0",
				}),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "debian_git01" {
					node_name = "{{.NodeName}}"
					started   = false
					name      = "git01"
					
					boot_order = ["scsi0", "net0"]
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 32
					}

					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 20
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi2"
						size         = 1
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi3"
						size         = 50
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi4"
						size         = 1
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi5"
						size         = 50
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi6"
						size         = 1
					}
				}`),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectResourceAction("proxmox_virtual_environment_vm.debian_git01", plancheck.ResourceActionUpdate),
						plancheck.ExpectNonEmptyPlan(),
					},
				},
				Check: ResourceAttributes("proxmox_virtual_environment_vm.debian_git01", map[string]string{
					"disk.#":           "7",
					"disk.0.interface": "scsi0",
					"disk.0.size":      "32",
					"disk.1.interface": "scsi1",
					"disk.1.size":      "20",
					"disk.2.interface": "scsi2",
					"disk.2.size":      "1",
					"disk.3.interface": "scsi3",
					"disk.3.size":      "50",
					"disk.4.interface": "scsi4",
					"disk.4.size":      "1",
					"disk.5.interface": "scsi5",
					"disk.5.size":      "50",
					"disk.6.interface": "scsi6",
					"disk.6.size":      "1",
					"boot_order.0":     "scsi0",
					"boot_order.1":     "net0",
				}),
			},
			{
				RefreshState: true,
			},
		}},
		{"efi disk", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_efi_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-efi-disk"

					efi_disk {
						datastore_id = "local-lvm"
						type = "4m"
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_efi_disk", map[string]string{
						"efi_disk.0.datastore_id": "local-lvm",
						"efi_disk.0.type":         "4m",
					}),
				),
			},
			{
				RefreshState: true,
			},
		}},
		{"efi disk parameter change issue 1515", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_efi_disk_change" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-efi-disk-change-1515"

					efi_disk {
						datastore_id = "local-lvm"
						type = "4m"
						pre_enrolled_keys = false
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_efi_disk_change", map[string]string{
						"efi_disk.0.datastore_id":      "local-lvm",
						"efi_disk.0.type":              "4m",
						"efi_disk.0.pre_enrolled_keys": "false",
					}),
				),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_efi_disk_change" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-efi-disk-change-1515"

					efi_disk {
						datastore_id = "local-lvm"
						type = "4m"
						pre_enrolled_keys = true
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_efi_disk_change", map[string]string{
						"efi_disk.0.pre_enrolled_keys": "true",
					}),
				),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectResourceAction("proxmox_virtual_environment_vm.test_efi_disk_change", plancheck.ResourceActionUpdate),
					},
				},
			},
		}},
		{"ide disks", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disks" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disks-ide"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "ide0"
						size         = 8
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disks", map[string]string{
					"disk.0.interface":         "ide0",
					"disk.0.path_in_datastore": `vm-\d+-disk-0`,
				}),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disks" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disks-ide"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "ide0"
						size         = 8
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "ide1"
						size         = 8
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disks", map[string]string{
					"disk.#": "2",
				}),
			},
			{
				RefreshState: true,
			},
		}},
		{"clone disk with overrides", []resource.TestStep{
			{
				SkipFunc: func() (bool, error) {
					// this test is failing because of https://github.com/bpg/terraform-provider-proxmox/issues/873
					return true, nil
				},
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk3_template" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk-template"
					template  = "true"
		
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
						discard      = "on"
						iothread     = true
						ssd          = true
					}
				}
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"
		
					clone {
						vm_id = proxmox_virtual_environment_vm.test_disk_template.id
					}
		
					disk {
						interface    = "scsi0"
						size = 10
					}
				}`),
				Check: ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
					"disk.0.datastore_id":      "local-lvm",
					"disk.0.discard":           "on",
					"disk.0.file_format":       "raw",
					"disk.0.interface":         "scsi0",
					"disk.0.iothread":          "true",
					"disk.0.path_in_datastore": `base-\d+-disk-\d+`,
					"disk.0.size":              "10",
					"disk.0.ssd":               "true",
				}),
			},
			{
				RefreshState: true,
				Destroy:      false,
			},
		}},
		{"clone with disk resize", []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_template" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk-template"
					template  = "true"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 8
					}
				}
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"

					clone {
						vm_id = proxmox_virtual_environment_vm.test_disk_template.id
					}

					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 10
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
						"disk.0.datastore_id": "local-lvm",
						"disk.0.interface":    "virtio0",
						"disk.0.size":         "10",
					}),
				),
			},
			{
				RefreshState: true,
			},
		}},
		{"clone with adding disk", []resource.TestStep{
			{
				SkipFunc: func() (bool, error) {
					// this test is failing because of "Attribute 'disk.1.size' expected to be set"
					return true, nil
				},
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_template" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk-template"
					template  = "true"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 8
					}
				}
				resource "proxmox_virtual_environment_vm" "test_disk" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-disk"

					clone {
						vm_id = proxmox_virtual_environment_vm.test_disk_template.id
					}

					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 10
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk", map[string]string{
						"disk.1.datastore_id": "local-lvm",
						"disk.1.interface":    "virtio0",
						"disk.1.size":         "8",
						"disk.0.datastore_id": "local-lvm",
						"disk.0.interface":    "scsi0",
						"disk.0.size":         "10",
					}),
				),
			},
			{
				RefreshState: true,
			},
		}},
		{"clone with updating disk attributes", []resource.TestStep{{
			Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "template" {
					node_name = "{{.NodeName}}"
					started   = false
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 20
					}
				}
				resource "proxmox_virtual_environment_vm" "clone" {
					node_name = "{{.NodeName}}"
					started   = false
					clone {
						vm_id = proxmox_virtual_environment_vm.template.vm_id
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						iothread     = true
						discard      = "on"
						size         = 30
						speed {
						  iops_read = 100
						  iops_read_burstable = 1000
						  iops_write = 400
						  iops_write_burstable = 800
						}
					}
				}`),
			Check: resource.ComposeTestCheckFunc(
				ResourceAttributes("proxmox_virtual_environment_vm.clone", map[string]string{
					"disk.0.iothread":                     "true",
					"disk.0.discard":                      "on",
					"disk.0.size":                         "30",
					"disk.0.speed.0.iops_read":            "100",
					"disk.0.speed.0.iops_read_burstable":  "1000",
					"disk.0.speed.0.iops_write":           "400",
					"disk.0.speed.0.iops_write_burstable": "800",
				}),
			),
		}}},
		{"clone with moving disk", []resource.TestStep{{
			Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "template" {
					node_name = "{{.NodeName}}"
					started   = false
					efi_disk {
						datastore_id = "local-lvm"
						type = "4m"
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "virtio0"
						size         = 20
					}
				}
				resource "proxmox_virtual_environment_vm" "clone" {
					node_name = "{{.NodeName}}"
					started   = false
					clone {
						vm_id = proxmox_virtual_environment_vm.template.vm_id
					}
					disk {
						datastore_id = "tank"
						interface    = "virtio0"
						size         = 20
					}
				}`),
			Check: resource.ComposeTestCheckFunc(
				ResourceAttributes("proxmox_virtual_environment_vm.clone", map[string]string{
					"disk.0.datastore_id": "tank",
				}),
			),
		}}},
		{"update single disk without affecting boot disk with import_from", []resource.TestStep{
			{
				// Create VM with boot disk that has import_from and a second disk
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_download_file" "test_boot_image" {
					content_type = "import"
					datastore_id = "local"
					node_name    = "{{.NodeName}}"
					url          = "{{.CloudImagesServer}}/minimal/releases/noble/release/ubuntu-24.04-minimal-cloudimg-amd64.img"
					file_name    = "test-bootdisk-bug-image.img.raw"
					overwrite_unmanaged = true
				}
				resource "proxmox_virtual_environment_vm" "test_bootdisk_bug" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-bootdisk-bug"
					
					disk {
						datastore_id = "local-lvm"
						import_from  = proxmox_virtual_environment_download_file.test_boot_image.id
						interface    = "scsi0"
						size         = 6
					}
					
					disk {
						datastore_id = "local-lvm" 
						interface    = "scsi1"
						size         = 1
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_bootdisk_bug", "disk.0.interface", "scsi0"),
					resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_bootdisk_bug", "disk.1.interface", "scsi1"),
					resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_bootdisk_bug", "disk.1.size", "1"),
				),
			},
			{
				// Update only scsi1 size from 1 to 2
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_download_file" "test_boot_image" {
					content_type = "import"
					datastore_id = "local"
					node_name    = "{{.NodeName}}"
					url          = "{{.CloudImagesServer}}/minimal/releases/noble/release/ubuntu-24.04-minimal-cloudimg-amd64.img"
					file_name    = "test-bootdisk-bug-image.img.raw"
					overwrite_unmanaged = true
				}
				resource "proxmox_virtual_environment_vm" "test_bootdisk_bug" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-bootdisk-bug"
					
					disk {
						datastore_id = "local-lvm"
						import_from  = proxmox_virtual_environment_download_file.test_boot_image.id
						interface    = "scsi0"
						size         = 6  // UNCHANGED - should not be sent to API
					}
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 2  // CHANGED - only this should be sent to API
					}
				}`),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectResourceAction("proxmox_virtual_environment_vm.test_bootdisk_bug", plancheck.ResourceActionUpdate),
					},
				},
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_bootdisk_bug", "disk.1.size", "2"),
				),
			},
		}},
		{"resize boot disk with import_from should not trigger re-import", []resource.TestStep{
			{
				// Create VM with boot disk using import_from
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_download_file" "test_boot_resize" {
					content_type = "import"
					datastore_id = "local"
					node_name    = "{{.NodeName}}"
					url          = "{{.CloudImagesServer}}/minimal/releases/noble/release/ubuntu-24.04-minimal-cloudimg-amd64.img"
					file_name    = "test-boot-resize-image.img.raw"
					overwrite_unmanaged = true
				}
				resource "proxmox_virtual_environment_vm" "test_boot_resize" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-boot-resize"
					
					disk {
						datastore_id = "local-lvm"
						import_from  = proxmox_virtual_environment_download_file.test_boot_resize.id
						interface    = "scsi0"
						size         = 8
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_boot_resize", "disk.0.interface", "scsi0"),
					resource.TestCheckResourceAttrSet("proxmox_virtual_environment_vm.test_boot_resize", "disk.0.path_in_datastore"),
				),
			},
			{
				// Resize the boot disk itself
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_download_file" "test_boot_resize" {
					content_type = "import"
					datastore_id = "local"
					node_name    = "{{.NodeName}}"
					url          = "{{.CloudImagesServer}}/minimal/releases/noble/release/ubuntu-24.04-minimal-cloudimg-amd64.img"
					file_name    = "test-boot-resize-image.img.raw"
					overwrite_unmanaged = true
				}
				resource "proxmox_virtual_environment_vm" "test_boot_resize" {
					node_name = "{{.NodeName}}"
					started   = false
					name 	  = "test-boot-resize"
					
					disk {
						datastore_id = "local-lvm"
						import_from  = proxmox_virtual_environment_download_file.test_boot_resize.id
						interface    = "scsi0"
						size         = 12  // Resize from 8 to 12 - should work now
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_boot_resize", "disk.0.size", "12"),
				),
			},
		}},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			resource.Test(t, resource.TestCase{
				ProtoV6ProviderFactories: te.AccProviders,
				Steps:                    tt.steps,
			})
		})
	}
}

// TestAccResourceVMDiskCloneNFSResize tests cloning a VM with disk resize to NFS storage.
// This is a regression test for https://github.com/bpg/terraform-provider-proxmox/issues/1599
// where disk resize fails on NFS storage with "volume does not exist" error due to
// NFS storage sync timing issues after disk move.
func TestAccResourceVMDiskCloneNFSResize(t *testing.T) {
	nfsDatastoreID := utils.GetAnyStringEnv("PROXMOX_VE_ACC_NFS_DATASTORE_ID")
	if nfsDatastoreID == "" {
		t.Skip("NFS storage is not available")
	}

	te := InitEnvironment(t)
	te.AddTemplateVars(map[string]any{
		"NFSDatastoreID": nfsDatastoreID,
	})

	resource.Test(t, resource.TestCase{
		ProtoV6ProviderFactories: te.AccProviders,
		Steps: []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "template_nfs_resize" {
					node_name = "{{.NodeName}}"
					started   = false
					name      = "test-template-nfs-resize"
					template  = true
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 8
					}
				}
				resource "proxmox_virtual_environment_vm" "clone_nfs_resize" {
					node_name = "{{.NodeName}}"
					started   = false
					name      = "test-clone-nfs-resize"

					clone {
						vm_id = proxmox_virtual_environment_vm.template_nfs_resize.vm_id
						full  = true
					}

					# Clone to NFS storage with disk resize - this is the scenario from issue #1599
					# The disk needs to be moved from local-lvm to NFS storage and resized.
					# On NFS storage, there can be a timing issue where the volume is not
					# immediately available for resize after the move operation completes.
					disk {
						datastore_id = "{{.NFSDatastoreID}}"
						interface    = "scsi0"
						size         = 10
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.clone_nfs_resize", map[string]string{
						"disk.0.datastore_id": nfsDatastoreID,
						"disk.0.interface":    "scsi0",
						"disk.0.size":         "10",
					}),
				),
			},
		},
	})
}

func TestAccResourceVMDiskRemovalReuseIssue2218(t *testing.T) {
	te := InitEnvironment(t)

	resource.Test(t, resource.TestCase{
		ProtoV6ProviderFactories: te.AccProviders,
		Steps: []resource.TestStep{
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_removal" {
					node_name = "{{.NodeName}}"
					started   = false
					name      = "test-disk-removal-2218"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 1
						serial       = "os_disk"
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 1
						serial       = "test_disk"
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk_removal", map[string]string{
						"disk.0.interface": "scsi0",
						"disk.0.size":      "1",
						"disk.0.serial":    "os_disk",
						"disk.1.interface": "scsi1",
						"disk.1.size":      "1",
						"disk.1.serial":    "test_disk",
					}),
				),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_removal" {
					node_name = "{{.NodeName}}"
					started   = false
					name      = "test-disk-removal-2218"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 1
						serial       = "os_disk"
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk_removal", map[string]string{
						"disk.0.interface": "scsi0",
						"disk.0.size":      "1",
						"disk.0.serial":    "os_disk",
						"disk.#":           "1",
					}),
				),
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_removal" {
					node_name = "{{.NodeName}}"
					started   = false
					name      = "test-disk-removal-2218"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 1
						serial       = "os_disk"
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 5
						serial       = "different_disk"
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk_removal", map[string]string{
						"disk.0.interface": "scsi0",
						"disk.0.size":      "1",
						"disk.0.serial":    "os_disk",
						"disk.1.interface": "scsi1",
						"disk.1.size":      "5",
						"disk.1.serial":    "different_disk",
						"disk.#":           "2",
					}),
				),
			},
			{
				RefreshState: true,
			},
			{
				Config: te.RenderConfig(`
				resource "proxmox_virtual_environment_vm" "test_disk_removal" {
					node_name = "{{.NodeName}}"
					started   = false
					name      = "test-disk-removal-2218"
					
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi0"
						size         = 1
						serial       = "os_disk"
					}
					disk {
						datastore_id = "local-lvm"
						interface    = "scsi1"
						size         = 5
						serial       = "different_disk"
					}
				}`),
				Check: resource.ComposeTestCheckFunc(
					ResourceAttributes("proxmox_virtual_environment_vm.test_disk_removal", map[string]string{
						"disk.1.size": "5",
					}),
				),
				ConfigPlanChecks: resource.ConfigPlanChecks{
					PreApply: []plancheck.PlanCheck{
						plancheck.ExpectEmptyPlan(),
					},
				},
			},
		},
	})
}
